package org.aeon.colorfulplanebattle.view.listener;

import org.aeon.colorfulplanebattle.flying.Utils;
import org.aeon.colorfulplanebattle.flying.entity.Plane;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Predicate;

import static org.aeon.colorfulplanebattle.constant.GameBasisConstant.*;
import static org.aeon.colorfulplanebattle.view.listener.SustainAttackE.SUSTAIN_ATTACK;
import static org.aeon.colorfulplanebattle.view.listener.SustainMoveE.*;

/**
 * @author: MissingAeon
 * @date: 2024/1/9 12:24
 * @description: 游戏键盘监听器
 */
public class GameKeyListener extends KeyAdapter {

    private static final GameKeyListener INSTANCE = new GameKeyListener();
    private static final Properties prop;

    static {
        prop = Utils.getProp(SUSTAIN);
    }

    private final ExecutorService keyboardExecutor;         // 线程池
    private Plane myPlane;

    private GameKeyListener() {
        keyboardExecutor = Executors.newFixedThreadPool(2);
    }

    public static GameKeyListener gameListener() {
        return INSTANCE;
    }

    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_W -> startAction(SUSTAIN_UP);
            case KeyEvent.VK_A -> startAction(SUSTAIN_LEFT);
            case KeyEvent.VK_S -> startAction(SUSTAIN_DOWN);
            case KeyEvent.VK_D -> startAction(SUSTAIN_RIGHT);
            case KeyEvent.VK_E -> myPlane.setChange(true);
            case KeyEvent.VK_SPACE -> startAction(SUSTAIN_ATTACK);
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_W -> endAction(SUSTAIN_UP);
            case KeyEvent.VK_A -> endAction(SUSTAIN_LEFT);
            case KeyEvent.VK_S -> endAction(SUSTAIN_DOWN);
            case KeyEvent.VK_D -> endAction(SUSTAIN_RIGHT);
            case KeyEvent.VK_SPACE -> endAction(SUSTAIN_ATTACK);
        }
    }

    private void endAction(Action sustainMove) {
        sustainMove.setFlag(false);
    }

    private void startAction(Action sustainMove) {
        sustainMove.setFlag(true);
        if (!SustainAttack.sustainAttack.flag) {
            SustainAttack.sustainAttack.flag = true;
            keyboardExecutor.execute(SustainAttack.sustainAttack);
        }
        if (!SustainMove.sustainMove.flag) {
            SustainMove.sustainMove.flag = true;
            keyboardExecutor.execute(SustainMove.sustainMove);
        }

    }

    public void setMyPlane(Plane myPlane) {
        this.myPlane = myPlane;
        SustainMoveE.setMyPlane(myPlane);
        SustainAttackE.setMyPlane(myPlane);
    }

    public void reset() {
        SustainMove.sustainMove.flag = false;
        SustainAttack.sustainAttack.flag = false;
        SUSTAIN_ATTACK.setFlag(false);
        Arrays.stream(values()).forEach(e -> e.setFlag(false));
    }

    private static class SustainAttack implements Runnable {
        static SustainAttack sustainAttack = new SustainAttack();
        long attackInterval = ATTACK_INTERVAL;
        boolean flag;

        private SustainAttack() {
            Utils.stuffing(prop, this);
        }

        @Override
        public void run() {
            while (flag) {
                SUSTAIN_ATTACK.run();
                if (!SUSTAIN_ATTACK.isFlag()) {
                    flag = false;
                    break;
                }
                try {
                    Thread.sleep(attackInterval);
                } catch (InterruptedException ignored) {
                }
            }
        }
    }

    private static class SustainMove implements Runnable {
        static SustainMove sustainMove = new SustainMove();
        private final SustainMoveE[] values;
        long moveInterval = MOVE_INTERVAL;            // 移动间隔
        boolean flag;

        private SustainMove() {
            values = values();
            Utils.stuffing(prop, this);
        }

        @Override
        public void run() {
            while (flag) {
                for (SustainMoveE value : values) {
                    value.run();
                }
                if (Arrays.stream(values).allMatch(Predicate.not(SustainMoveE::isFlag))) {
                    flag = false;
                    break;
                }
                try {
                    Thread.sleep(moveInterval);
                } catch (InterruptedException ignored) {
                }
            }
        }
    }

}
